#include "../include/head.h"
#include "../include/func.h"

int removeTrailingSpace(char* str) {
    int length = strlen(str);
    if (length > 0 && str[length - 1] == ' ') {
        str[length - 1] = '\0';
    } else {
        return -1;
    }
    return 0;
}

int generateMD5(const char *filename, char *md5String) {
    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    unsigned char md_value[EVP_MAX_MD_SIZE];
    unsigned int md_len, i;
    FILE *file;
    int bytes;
    unsigned char data[1024];

    // 初始化上下文
    mdctx = EVP_MD_CTX_new();
    if (mdctx == NULL) {
        printf("EVP_MD_CTX_new failed\n");
        return -1;
    }

    // 使用MD5算法
    md = EVP_md5();
    if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
        printf("EVP_DigestInit_ex failed\n");
        EVP_MD_CTX_free(mdctx);
        return -1;
    }

    // 打开文件
    file = fopen(filename, "rb");
    if (file == NULL) {
        printf("%s can't be opened.\n", filename);
        EVP_MD_CTX_free(mdctx);
        return -1;
    }

    // 读取文件并更新MD5上下文
    while ((bytes = fread(data, 1, 1024, file)) != 0) {
        if (EVP_DigestUpdate(mdctx, data, bytes) != 1) {
            printf("EVP_DigestUpdate failed\n");
            fclose(file);
            EVP_MD_CTX_free(mdctx);
            return -1;
        }
    }

    // 完成哈希计算
    if (EVP_DigestFinal_ex(mdctx, md_value, &md_len) != 1) {
        printf("EVP_DigestFinal_ex failed\n");
        fclose(file);
        EVP_MD_CTX_free(mdctx);
        return -1;
    }

    // 释放上下文
    EVP_MD_CTX_free(mdctx);
    fclose(file);

    // 将MD5值转换为十六进制字符串
    for (i = 0; i < md_len; i++) {
        sprintf(&md5String[i * 2], "%02x", md_value[i]);
    }
    md5String[md_len * 2] = '\0';
    return 0;
}

int putsCommand(int sockfd, train_t * pt) {
    
    char response[64] = {0};
    // 1. 客户端先发送md5的值给服务端
    // 1.1 获取要上传文件的文件名
    char filename[20] = {0};
    removeTrailingSpace(pt->buff);
    strcpy(filename, pt->buff);

    // 1.2 根据文件内容，生成md5值
    char md5String[33];
    generateMD5(filename, md5String);

    
    // 1.3 发送给服务端md5值
    send(sockfd, md5String, sizeof(md5String), 0);
    // printf("md5码值为：%s\n",md5String);
    
    // 2. 接受客户端返回的结果
    int ret = -1;
    recv(sockfd, &ret, sizeof(int), MSG_WAITALL);
    // printf("客户端收到的结果是%d\n", ret);

    // 2.1 文件存在ret = 1，实现文件秒传;
    if (ret == 1) {
        // 接受客户端发送的响应信息
        int reslength;
        recv(sockfd, &reslength, sizeof(int), MSG_WAITALL);
        // printf("%d\n", reslength);
        recv(sockfd, response, reslength, MSG_WAITALL);
        printf("%s\n", response);
    }
    // 3. 文件不存在ret = 0,向客户端发送文件名，文件长度，文件内容
    else if (ret == 0) {
        // 3.1 向服务器发送文件长度
        // 3.1.1 获取文件大小
        int fd = open(filename, O_RDWR);
        if (fd == -1) {
            printf("文件不存在，请确认后再上传!\n");
            return -1;
        }

        struct stat st;
        memset(&st, 0, sizeof(st));
        fstat(fd, &st);
        long int filelength = st.st_size;
       //  printf("file length: %ld\n", filelength);
        // 3.1.2 发送文件大小
        send(sockfd, &filelength, sizeof(filelength), 0);
        
        // 3.2 发送文件内容
        char buff[1000];
        off_t curr = 0;
        // 用于打印进度条
        off_t splice = filelength / 100;
        off_t lastSize = 0;

        int ret = 0;
        while (curr < filelength) {
            bzero(buff, sizeof(buff));
            ret = read(fd, buff, sizeof(buff));
            if (ret == 0) {
                break;
            }
            ret = send(sockfd, buff, ret, 0);
            curr += ret;
            if (curr - lastSize > splice) {
                printf("\033[35m文件正在火速上传---%5.2lf%%\r\033[0m", (double)curr/filelength * 100);
                fflush(stdout);
                lastSize = curr;
            }
        }
        printf("\033[35m文件成功完成上传---100.00%%\n\033[0m");
               
        fflush(stdout);

        close(fd);
        
        // 3.3 接受服务器返回的信息
        recv(sockfd, response, sizeof(response), MSG_WAITALL);
        printf("%s\n", response);

    }
    return 0;
}

int getsCommand(int sockfd, train_t * pt) {

    // 客户端
    // 1. 接受客户端发送的内容，查看是否存在
    // 2. 文件存在，查询本地是否存在文件，发送offset
    // 3. 接收客户端发送的内容
    removeTrailingSpace(pt->buff);

    char* filename = pt->buff;  
    
    // 1. 接受服务器发送的文件是否存在的标记
    int flag;
    recv(sockfd, &flag, sizeof(flag), MSG_WAITALL);
    // printf("客户端收到的标志位是:%d", flag);

    // 1.1 flag = 0 文件不存在
    if (flag == 0) {
        printf("目标文件不存在!\n");
        return -1;
    } 
    
    // flag = 1 服务器端文件存在
    
    // 2. 接受客户端发送的文件长度
    int fileLength;
    recv(sockfd, &fileLength, sizeof(fileLength), MSG_WAITALL);

    // 3.1 进度条
    // off_t splice = fileLength / 100;
    // off_t currSize = 0;
    // off_t lastSize = 0;
    
    // 2.1 打开文件
    int fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0664);

    // 3 接收文件内容
    char buff[1000] = {0};
    int ret = 0;
    int left = fileLength;
    // 3.1 进度条
    off_t splice = fileLength / 100;
    off_t currSize = 0;
    off_t lastSize = 0;
    while (left > 0) {
        if (left < 1000) {
            ret = recv(sockfd, buff, left, MSG_WAITALL);
        } else {
            ret = recv(sockfd, buff, sizeof(buff), MSG_WAITALL);
        }
        if (ret < 0) {
            break;
        }
        ret = write(fd, buff, ret);
        left -= ret;
        // 进度条
        currSize += ret;
        if (currSize - lastSize > splice) {
            printf("\033[35m文件正在火速下载---%5.2lf%%\r\033[0m", (double)currSize/fileLength * 100);
            fflush(stdout);
            lastSize = currSize;
        }
    }
    printf("\033[35m文件成功完成下载---100.00%%\n\033[0m");
    close(fd);

    printf("接收完毕！\n");
    return 0;
}